package com.letv.core.network.volley;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;

import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;

import com.letv.core.bean.LetvBaseBean;
import com.letv.core.network.volley.VolleyRequest.RequestManner;
import com.letv.core.network.volley.VolleyResponse.CacheResponseState;
import com.letv.core.network.volley.VolleyResponse.NetworkResponseState;
import com.letv.core.network.volley.listener.Network;
import com.letv.core.network.volley.listener.ResponseDelivery;
import com.letv.core.network.volley.toolbox.VolleyNoCache;
import com.letv.core.utils.BaseTypeUtils;

/**
 * 请求队列
 * 
 * @author zhuqiao
 * 
 */
public class VolleyRequestQueue {
    /** 子线程数量 **/
    private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 5;
    private static final int DEFAULT_CACHE_THREAD_POOL_SIZE = 3;

    /** 给请求生成自增序列号 **/
    private AtomicInteger mSequenceGenerator = new AtomicInteger();

    /** 所有在队列中，或者正在被处理的请求都会在这个集合中 **/
    private final Set<VolleyRequest<?>> mCurrentRequests = new HashSet<VolleyRequest<?>>();

    /** 需要进行缓存访问的请求队列(根据优先级顺序执行) **/
    private final PriorityBlockingQueue<VolleyRequest<?>> mCacheQueue = new PriorityBlockingQueue<VolleyRequest<?>>();

    /** 需要进行网络访问的请求队列(根据优先级顺序执行) **/
    private final PriorityBlockingQueue<VolleyRequest<?>> mNetworkQueue = new PriorityBlockingQueue<VolleyRequest<?>>();

    /** 需要进行网络访问上传文件的请求队列(根据优先级顺序执行) **/
    private final PriorityBlockingQueue<VolleyRequest<?>> mFileNetworkQueue = new PriorityBlockingQueue<VolleyRequest<?>>();

    /** 真正执行http请求的网络接口 **/
    private final Network mNetwork;

    /** 上传文件http请求的网络接口 **/
    private final Network mFileNetwork;

    /** 将请求响应进行解析并交付给请求发起者 **/
    private final ResponseDelivery mDelivery;

    /** 网络请求调度器 **/
    private NetworkDispatcher[] mDispatchers;

    /** 上传文件请求调度器 **/
    private NetworkDispatcher mFileDispatcher;

    /** 缓存请求调度器 **/
    private CacheDispatcher[] mCacheDispatchers;

    public VolleyRequestQueue(Network network, Network fileNetwork, int threadPoolSize, int cacheThreadPoolSize,
            ResponseDelivery delivery) {
        mNetwork = network;
        mFileNetwork = fileNetwork;
        mDispatchers = new NetworkDispatcher[threadPoolSize];
        mCacheDispatchers = new CacheDispatcher[cacheThreadPoolSize];
        mDelivery = delivery;
    }

    public VolleyRequestQueue(Network network, Network fileNetwork, int threadPoolSize, int cacheThreadPoolSize) {
        this(network, fileNetwork, threadPoolSize, cacheThreadPoolSize, new ExecutorDelivery(new Handler(
                Looper.getMainLooper())));
    }

    public VolleyRequestQueue(Network network, Network fileNetwork) {
        this(network, fileNetwork, DEFAULT_NETWORK_THREAD_POOL_SIZE, DEFAULT_CACHE_THREAD_POOL_SIZE);
    }

    /**
     * 开启所有调度器
     */
    public void start() {
        // 确保当前所有正在运行的调度器已经停止
        stop();

        for (int i = 0; i < mCacheDispatchers.length; i++) {
            CacheDispatcher dispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mDelivery);
            mCacheDispatchers[i] = dispatcher;
            dispatcher.start();
        }

        for (int i = 0; i < mDispatchers.length; i++) {
            NetworkDispatcher dispatcher = new NetworkDispatcher(mNetworkQueue, mCacheQueue, mNetwork, mDelivery);
            mDispatchers[i] = dispatcher;
            dispatcher.start();
        }

        mFileDispatcher = new NetworkDispatcher(mFileNetworkQueue, mCacheQueue, mFileNetwork, mDelivery);
        mFileDispatcher.start();
    }

    /**
     * 停止所有调度器
     */
    public void stop() {
        for (int i = 0; i < mCacheDispatchers.length; i++) {
            if (mCacheDispatchers[i] != null) {
                mCacheDispatchers[i].quit();
            }
        }

        for (int i = 0; i < mDispatchers.length; i++) {
            if (mDispatchers[i] != null) {
                mDispatchers[i].quit();
            }
        }

        if (mFileDispatcher != null) {
            mFileDispatcher.quit();
        }
    }

    /**
     * 添加请求到调度器队列里
     * 
     * @param request
     * @return
     */
    public VolleyRequest<?> add(VolleyRequest<?> request) {
        if (!request.onPreExecute()) {
            // 验证不通过,那么不需要发起真正的请求
            request.validateFail();
        }

        request.setRequestQueue(this);

        synchronized (mCurrentRequests) {
            // 表示正在或即将被处理的请求
            mCurrentRequests.add(request);
        }

        // 设置序列号
        request.setSequence(getSequenceNumber());

        if (containPostFile(request)) {
            // 文件上传请求
            request.setRequestType(RequestManner.NETWORK_ONLY);
            request.setCache(new VolleyNoCache());
            mFileNetworkQueue.add(request);
        } else {
            // 普通请求
            RequestManner type = request.mRequestType;
            // 判断内部请求方式
            if (type == RequestManner.NETWORK_ONLY || type == RequestManner.NETWORK_THEN_CACHE) {
                mNetworkQueue.add(request);
            } else {
                mCacheQueue.add(request);
            }
        }

        return request;
    }

    /**
     * 同步请求
     * 
     * @param request
     */
    public <T extends LetvBaseBean> VolleyResult<T> syncFetch(VolleyRequest<T> request) {
        VolleyResult<T> result;
        if (containPostFile(request)) {
            // 上传文件
            request.setRequestType(RequestManner.NETWORK_ONLY);
            request.setCache(new VolleyNoCache());
            result = new NetworkRequestData<T>(mDelivery, mFileNetwork, true).start(request);
        } else {
            RequestManner type = request.mRequestType;
            if (type == RequestManner.NETWORK_ONLY || type == RequestManner.NETWORK_THEN_CACHE) {
                // 容错，同步请求只能是NETWORK_ONLY或者CACHE_ONLY
                result = new NetworkRequestData<T>(mDelivery, mNetwork, true).start(request);
            } else {
                result = new CacheRequestData<T>(mDelivery, true).start(request);
            }
        }

        if (result == null) {
            // 容错
            return new VolleyResult<T>(null, request.mNetWorkDataHull, NetworkResponseState.IGNORE,
                    CacheResponseState.IGNORE, "");
        }
        return result;
    }

    /**
     * 是否包含文件上传
     * 
     * @param request
     * @return
     */
    private boolean containPostFile(VolleyRequest<?> request) {
        return !BaseTypeUtils.isArrayEmpty(request.getFileBody());
    }

    private int getSequenceNumber() {
        return mSequenceGenerator.incrementAndGet();
    }

    public interface RequestFilter {

        boolean apply(VolleyRequest<?> request);
    }

    /**
     * 根据过滤取消请求
     * 
     * @param filter
     */
    public void cancelAll(RequestFilter filter) {
        synchronized (mCurrentRequests) {
            for (VolleyRequest<?> request : mCurrentRequests) {
                if (filter == null) {
                    request.cancel();
                } else if (filter.apply(request)) {
                    request.cancel();
                }
            }
        }
    }

    /**
     * 根据tag取消特定的request
     * 
     * @param tag
     */
    public void cancelWithTag(final String tag) {
        if (TextUtils.isEmpty(tag)) {
            return;
        }

        cancelAll(new RequestFilter() {

            @Override
            public boolean apply(VolleyRequest<?> request) {
                return TextUtils.equals(request.getTag(), tag);
            }
        });
    }

    public void finish(VolleyRequest<?> request) {
        synchronized (mCurrentRequests) {
            mCurrentRequests.remove(request);
        }
    }

    public void finishAll() {
        synchronized (mCurrentRequests) {
            mCurrentRequests.clear();
        }
    }

    public void onDestory() {
        cancelAll(null);
        finishAll();
    }
}
